#r "nuget: Newtonsoft.Json, 13.0.3"
#r "nuget: PuppeteerSharp, 20.2.2"

using PuppeteerSharp;
using PuppeteerSharp.BrowserData;
using Newtonsoft.Json;
using System.Xml;



public class NatsumeSchedule
{
    public string gameweek;
    public List<DateModel> days = new List<DateModel>();

    public class DateModel
    {
        public string date;
        public EventsHolder events = new EventsHolder();

        public float GetSize()
        {
            var cardExtraHeight = 2.2f;
            return cardExtraHeight + events.GetSize();
        }

    }
    public class EventsHolder
    {
        public List<ScheduleItem> day = new List<ScheduleItem>();
        public List<ScheduleItem> evening = new List<ScheduleItem>();
        public List<ScheduleItem> night = new List<ScheduleItem>();

        public float GetSize()
        {

            float GetInternalSize(List<ScheduleItem> which)
            {
                if (which.Count == 0)
                {
                    return 0;
                }
                var dayTitleHeight = 1.8f;
                return which.Sum(f => f.GetSize()) + dayTitleHeight;
            }

            return GetInternalSize(day) + GetInternalSize(evening) + GetInternalSize(night);
        }
    }
    public class ScheduleItem
    {
        public string title;
        public string footnote;

        public float GetSize()
        {
            var basicSize = 1;
            if (title.Length > 40)
            {
                basicSize += 1;
            }
            if (footnote != null)
            {
                basicSize += 1;
            }
            return basicSize + 0.1f;
        }
    }
}
public class PartialDay
{
    public string date;
    public NatsumeSchedule.EventsHolder events = new NatsumeSchedule.EventsHolder();
    public bool isContinuation; // 标记是否延续前一天（用于渲染时判断是否显示日期）

    public float GetSize()
    {
        var cardExtraHeight = isContinuation ? 0 : 2.2f; // 如果是延续则不显示日期，节省高度
        return cardExtraHeight + events.GetSize();
    }
}

public class Page
{
    public List<PartialDay> contents = new List<PartialDay>();
    public float GetSize()
    {
        return contents.Sum(s => s.GetSize());
    }
}

public class ConvertedPage{
    public List<NatsumeSchedule.DateModel> contents = new List<NatsumeSchedule.DateModel>();     
    
    public ConvertedPage(Page p){
        var gb = p.contents.GroupBy(g => g.date);

        foreach (var item in gb)
        {
            NatsumeSchedule.DateModel newData = new NatsumeSchedule.DateModel();
            newData.date = item.Key;
            newData.events.day = item.SelectMany(s => s.events.day).ToList();
            newData.events.evening = item.SelectMany(s => s.events.evening).ToList();
            newData.events.night = item.SelectMany(s => s.events.night).ToList();
            contents.Add(newData);
        }
        
    }
    
}


var dataModel = JsonConvert.DeserializeObject<List<NatsumeSchedule>>(File.ReadAllText("../out/GameWeeks.json"));
var maxPageHeight = 42;


// 辅助方法：创建PartialDay
PartialDay CreatePartial(NatsumeSchedule.DateModel day, bool showDate)
{
    return new PartialDay
    {
        date = day.date,
        isContinuation = !showDate // 如果显示日期则不是延续
    };
}

// 辅助方法：添加到页面（处理分页逻辑）
void AddToPage(PartialDay partial, ref Page currentPage, ref List<Page> pages, float maxHeight)
{
    float partialSize = partial.GetSize();
    float currentSize = currentPage.GetSize();

    // 如果当前页空间不足
    if (currentSize + partialSize > maxHeight)
    {
        // 当前页有内容时先保存
        if (currentPage.contents.Count > 0)
        {
            pages.Add(currentPage);
            currentPage = new Page();
            currentSize = 0;
        }

        // 独立时段过大时强制放入新页
        if (partialSize > maxHeight)
        {
            // 先保存当前页（可能为空）
            if (currentSize > 0)
            {
                pages.Add(currentPage);
                currentPage = new Page();
            }
            currentPage.contents.Add(partial);
            pages.Add(currentPage);
            currentPage = new Page();
            return;
        }
    }

    // 添加到当前页
    currentPage.contents.Add(partial);
}



List<(string, List<Page>)> paginationedData = new List<(string, List<Page>)>();
foreach (var item in dataModel)
{
    List<Page> pages = new List<Page>();
    Page currentPage = new Page();
    bool isNewDay = true; // 标记是否是新的一天（需要显示日期）

    foreach (var day in item.days)
    {
        // 处理day时段
        if (day.events.day.Count > 0)
        {
            var partial = CreatePartial(day, isNewDay);
            partial.events.day = day.events.day;
            AddToPage(partial, ref currentPage, ref pages, maxPageHeight);
            isNewDay = false;
        }

        // 处理evening时段
        if (day.events.evening.Count > 0)
        {
            var partial = CreatePartial(day, isNewDay);
            partial.events.evening = day.events.evening;
            AddToPage(partial, ref currentPage, ref pages, maxPageHeight);
            isNewDay = false;
        }

        // 处理night时段
        if (day.events.night.Count > 0)
        {
            var partial = CreatePartial(day, isNewDay);
            partial.events.night = day.events.night;
            AddToPage(partial, ref currentPage, ref pages, maxPageHeight);
            isNewDay = false;
        }

        // 重置为下一天需要显示日期
        isNewDay = true;
    }

    // 添加最后一页
    if (currentPage.contents.Count > 0)
    {
        pages.Add(currentPage);
    }
    paginationedData.Add((item.gameweek, pages));
}



var cacheDir = Path.Combine(Environment.CurrentDirectory, ".puppeteer");
if (!Directory.Exists(cacheDir))
{
    Directory.CreateDirectory(cacheDir);
}

var browserDataDir = Path.Combine(cacheDir, ".userdata");

if (!Directory.Exists(browserDataDir))
{
    Directory.CreateDirectory(browserDataDir);
}

var outDir = Path.Combine("..", "out", "rednote");

if (!Directory.Exists(outDir))
{
    Directory.CreateDirectory(outDir);
}


var browserFetcher = Puppeteer.CreateBrowserFetcher(new BrowserFetcherOptions()
{
    Path = cacheDir
});

if (browserFetcher.GetInstalledBrowsers().Count() == 0)
{
    browserFetcher.DownloadAsync().GetAwaiter().GetResult();
}

Console.WriteLine("Browser initialzied. ");

string htmlContent = File.ReadAllText("rednote_template.html");

// 2. 启动无头浏览器
using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
    Headless = true,
    ExecutablePath = browserFetcher.GetInstalledBrowsers().First().GetExecutablePath(),
    Args = new[] { "--no-sandbox" },
    UserDataDir = browserDataDir,
}))
{
    // 3. 创建新页面
    using (var page = await browser.NewPageAsync())
    {
        // 4. 设置页面内容（也可加载URL）
        await page.SetContentAsync(htmlContent);
        await page.SetViewportAsync(new ViewPortOptions
        {
            Width = 420,
            DeviceScaleFactor = 2 // 提高截图质量
        });
        await page.WaitForExpressionAsync("window.isScriptDone");

        foreach (var gameWeeks in paginationedData)
        {
            var outDir = Path.Combine("..","out","rednote",gameWeeks.Item1);
            if(!Directory.Exists(outDir)){
                Directory.CreateDirectory(outDir);
            }
            int current = 1;
            int total = gameWeeks.Item2.Count;
            foreach (var gamePage in gameWeeks.Item2)
            {
                var pageJsonData = JsonConvert.SerializeObject(new ConvertedPage(gamePage).contents);
                var callFunction = $"window.SetData({current},{total},{pageJsonData})";
                await page.EvaluateExpressionAsync(callFunction);
                await page.WaitForExpressionAsync("window.isScriptDone");
                await page.ScreenshotAsync(Path.Combine(outDir,$"Page_{current:00}.png"),new ScreenshotOptions(){
                 FullPage = true,
                 
                });
                Console.WriteLine($"{current}/{total}");
                current++;
            }
  
        }
    
    }
}

Console.WriteLine("Done.");

